<?php
/**
 * 汇友科技
 * @copyright (c) 2017 http://www.huiyou365.net All rights reserved.
 * @author: Creatint <creatint@163.com>
 */

/**
 * 常量配置
 */
define('YO_AUTH_KEY','A%+aD`2]Zs~toBC/>p&Rc^r*09adf');// 密钥
const YO_ADDON_PATH = '../Addons/';

/**
 * 检测验证码
 * @param  integer $id 验证码ID
 * @return boolean     检测结果
 */
function check_verify($code, $id = 1){
    $verify = new \Think\Verify();
    return $verify->check($code, $id);
}


/**
 * 系统非常规MD5加密方法
 * @param  string $str 要加密的字符串
 * @return string
 */
function yo_md5($str, $key = YO_AUTH_KEY){
    return '' === $str ? '' : md5(sha1($str) . $key);
}

/**
 * 检测用户是否登录
 * @return integer 0-未登录，大于0-当前登录用户ID
 */
function is_login_admin(){
    // 尝试从session中获取登录的用户信息
    $user = session('user_auth');
    if (empty($user)) {
        return 0;
    } else {
        // 如果存在session，校验签名(data_auth_sign)是否正确
        return session('user_auth_sign') == data_auth_sign($user) ? $user['uid'] : 0;
    }
}

/**
 * 检测用户是否登录
 * @return integer 0-未登录，大于0-当前登录用户ID
 */
function is_login(){
    // 尝试从session中获取登录的用户信息
    $user = session('user');
    if (empty($user)) {
        return 0;
    } else {
        // 如果存在session，校验签名(data_auth_sign)是否正确
        return session('user_auth_sign') == data_auth_sign($user) ? $user['uid'] : 0;
    }
}


/**
 * 数据签名认证
 * @param  array  $data 被认证的数据
 * @return string       签名
 */
function data_auth_sign($data) {
    //数据类型检测
    if(!is_array($data)){
        $data = (array)$data;
    }
    ksort($data); //排序
    $code = http_build_query($data); //url编码并生成query字符串
    $sign = sha1($code); //生成签名
    return $sign;
}


/**
 * 系统加密方法
 * @param string $data 要加密的字符串
 * @param string $key  加密密钥
 * @param int $expire  过期时间 单位 秒
 * @return string
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function think_encrypt($data, $key = '', $expire = 0) {
    $key  = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
    $data = base64_encode($data);
    $x    = 0;
    $len  = strlen($data);
    $l    = strlen($key);
    $char = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    $str = sprintf('%010d', $expire ? $expire + time():0);

    for ($i = 0; $i < $len; $i++) {
        $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1)))%256);
    }
    return str_replace(array('+','/','='),array('-','_',''),base64_encode($str));
}

/**
 * 系统解密方法
 * @param  string $data 要解密的字符串 （必须是think_encrypt方法加密的字符串）
 * @param  string $key  加密密钥
 * @return string
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function think_decrypt($data, $key = ''){
    $key    = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
    $data   = str_replace(array('-','_'),array('+','/'),$data);
    $mod4   = strlen($data) % 4;
    if ($mod4) {
        $data .= substr('====', $mod4);
    }
    $data   = base64_decode($data);
    $expire = substr($data,0,10);
    $data   = substr($data,10);

    if($expire > 0 && $expire < time()) {
        return '';
    }
    $x      = 0;
    $len    = strlen($data);
    $l      = strlen($key);
    $char   = $str = '';

    for ($i = 0; $i < $len; $i++) {
        if ($x == $l) $x = 0;
        $char .= substr($key, $x, 1);
        $x++;
    }

    for ($i = 0; $i < $len; $i++) {
        if (ord(substr($data, $i, 1))<ord(substr($char, $i, 1))) {
            $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
        }else{
            $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
        }
    }
    return base64_decode($str);
}

/**
 * 对分页实例进行设置.
 *
 * @param $Page Think\Page 分页实例
 * @return null|string 分页html字符串
 */
function show_page($Page){
    if( !($Page instanceof Think\Page) ){
        return null;
    }
    $Page
        ->setConfig('type',C('PAGE_TYPE'))
        ->setConfig('first', C('PAGE_FIRST'))
        ->setConfig('last', C('PAGE_LAST'))
        ->setConfig('prev', C('PAGE_PREV'))
        ->setConfig('next', C('PAGE_NEXT'))
        ->setConfig('class_active', C('PAGE_CLASS_ACTIVE'))   // 当前按钮的样式
        ->setConfig('tag_parent',null)  // 分页组件的父级标签值为空
        ->setConfig('theme','%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%');

    return $Page->show();
}


/**
 * select返回的数组进行整数映射转换
 *
 * @param array $map  映射关系二维数组  array(
 *                                          '字段名1'=>array(映射关系数组),
 *                                          '字段名2'=>array(映射关系数组),
 *                                           ......
 *                                       )
 * @author 朱亚杰 <zhuyajie@topthink.net>
 * @return array
 *
 *  array(
 *      array('id'=>1,'title'=>'标题','status'=>'1','status_text'=>'正常')
 *      ....
 *  )
 *
 */
function int_to_string(&$data,$map=array('status'=>array(1=>'正常',-1=>'删除',0=>'禁用',2=>'未审核',3=>'草稿'))) {
    if($data === false || $data === null ){
        return $data;
    }
    $data = (array)$data;
    foreach ($data as $key => $row){
        foreach ($map as $col=>$pair){
            if(isset($row[$col]) && isset($pair[$row[$col]])){
                $data[$key][$col.'_text'] = $pair[$row[$col]];
            }
        }
    }
    return $data;
}




/**
 * 把返回的数据集转换成Tree
 * @param array $list 要转换的数据集
 * @param string $pid parent标记字段
 * @param string $level level标记字段
 * @return array
 * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 */
function list_to_tree($list, $pk='id', $pid = 'pid', $child = '_child', $root = 0) {
    // 创建Tree
    $tree = array();
    if(is_array($list)) {
        // 创建基于主键的数组引用
        $refer = array();
        foreach ($list as $key => $data) {
            $refer[$data[$pk]] =& $list[$key];
        }
        foreach ($list as $key => $data) {
            // 判断是否存在parent
            $parentId =  $data[$pid];
            if ($root == $parentId) {
                $tree[] =& $list[$key];
            }else{
                if (isset($refer[$parentId])) {
                    $parent =& $refer[$parentId];
                    $parent[$child][] =& $list[$key];
                }
            }
        }
    }
    return $tree;
}

/**
 * 获取缩进符号 tab_sign.
 *
 * @param $id 当前层级的id
 */
function get_tab_sign($id,$model = 'Category'){
    // TODO:使用缓存
    $list = D($model)->get([], true, 'sort asc,id asc', false);
    $refer = [];
    foreach ( $list as $key=>$value ) {
        $refer[$value['id']] = & $list[$key];
    }

    // 当前元素的id
    $current_key = $id;
    // 是否是最右侧的tab_sign
    $first = true;
    // 打印字符串
    $parse = '';

    for(;;){
        // 如果存在父级元素
        if ( $refer[$current_key]['pid']>0 ) {
            // 如果是最右侧的tab_sign
            if ( $first ) {
                // 判断当前元素是否其父元素中最后一个元素
                if ( arr_is_last(arr_search($refer, 'pid', $refer[$current_key]['pid']), $refer[$current_key]['id']) ) {
                    // 显示符号┗
                    $parse = '<span class="tab-sign first"></span>'.$parse;
                } else {
                    // 显示符号┠
                    $parse = '<span class="tab-sign tline"></span>'.$parse;
                }
                $first = false;
            } else {
                // 判断当前元素是否其父元素中最后一个元素
                if ( arr_is_last(arr_search($refer, 'pid', $refer[$current_key]['pid']), $refer[$current_key]['id']) ) {
                    // 不显示符号
                    $parse = '<span class="tab-sign clear"></span>'. $parse;
                } else {
                    // 显示符号│
                    $parse = '<span class="tab-sign line"></span>'. $parse;
                }
            }
            // 改变当前元素的id
            $current_key = $refer[$current_key]['pid'];
        } else {
            break;
        }
    }
    echo $parse;
}


function get_category_menu($list){

}


/**
 * 二维数组对某一字段的搜索,返回key的一维数组.
 *
 * @param $arr
 * @param $key
 * @param $value
 * @return array
 */
function arr_search($arr,$key,$value){
    $res = [];
    foreach ($arr as $k=>$v){
        if ( $v[$key] == $value ) {
            $res[] = $k;
        }
    }
    return $res;
}
/*
 * 一维数组 尾元素是否与给定值相同
 */
function arr_is_last($arr, $value){
    return end($arr) == $value;
}


// 获取数据的状态操作
function show_status_op($status) {
    switch ($status){
        case 0  : return    '启用';     break;
        case 1  : return    '禁用';     break;
        case 2  : return    '审核';       break;
        default : return    false;      break;
    }
}




// 分析枚举类型配置值 格式 a:名称1,b:名称2
function parse_config_attr($string) {
    $array = preg_split('/[,;\r\n]+/', trim($string, ",;\r\n"));
    if(strpos($string,':')){
        $value  =   array();
        foreach ($array as $val) {
            list($k, $v) = explode(':', $val);
            $value[$k]   = $v;
        }
    }else{
        $value  =   $array;
    }
    return $value;
}


/**
 * 认证白名单.
 *
 * @param $whiteList
 * @return bool
 */
function check_white_list($whiteList){
    // 默认当前控制器及方法不在白名单
    $res = 0;
    foreach( $whiteList as $key => $value ) {
        if ( is_numeric($key) && $value && is_string($value) && CONTROLLER_NAME === $value ){
            return true;
        } elseif( is_string($key) && $value && is_array($value) ){
            if ( CONTROLLER_NAME === $key ) {
                foreach( $value as $k => $v ) {
                    if ( $v && ACTION_NAME === $v ) {
                        return true;
                    }
                }
            }

        }
    }
    return false;
}


function get_array_level($arr){
    if ( count($arr) == count($arr,1) ) {
        return false;
    } else {
        return true;
    }
}

function array_merge2($arr){
    $res = [];
    foreach($arr as $v){
        $res = array_merge($v,$res);
    }
    return $res;
}

function array_id_key($arr,$key = 'id'){
    $res = [];
    if ( get_array_level($arr) ) {
        foreach( $arr as $v ){
            $res[$v[$key]] = $v;
        }
        return $res;
    } else{
        return [$arr[$key]=>$arr];
    }
}



/**
 * 获取属性信息并缓存
 * @param  integer $id    属性ID
 * @param  string  $field 要获取的字段名
 * @return string         属性信息
 */
function get_model_attribute($model_id, $group = true,$fields=true){
    static $list;

    /* 非法ID */
    if(empty($model_id) || !is_numeric($model_id)){
        return '';
    }

    /* 获取属性 */
    if(!isset($list[$model_id])){
        $map = array('model_id'=>$model_id);
        $extend = M('Model')->getFieldById($model_id,'extend');

        if($extend){
            $map = array('model_id'=> array("in", array($model_id, $extend)));
        }
        $info = M('Field')->where($map)->field($fields)->select();
        $list[$model_id] = $info;
    }

    $attr = array();
    if($group){
        foreach ($list[$model_id] as $value) {
            $attr[$value['id']] = $value;
        }
        $model     = M("Model")->field("field_sort,attribute_list,attribute_alias")->find($model_id);
        $attribute = explode(",", $model['attribute_list']);
        if (empty($model['field_sort'])) { //未排序
            $group = array(1 => array_merge($attr));
        } else {
            $group = json_decode($model['field_sort'], true);

            $keys = array_keys($group);
            foreach ($group as &$value) {
                foreach ($value as $key => $val) {
                    $value[$key] = $attr[$val];
                    unset($attr[$val]);
                }
            }

            if (!empty($attr)) {
                foreach ($attr as $key => $val) {
                    if (!in_array($val['id'], $attribute)) {
                        unset($attr[$key]);
                    }
                }
                $group[$keys[0]] = array_merge($group[$keys[0]], $attr);
            }
        }
        if (!empty($model['attribute_alias'])) {
            $alias  = preg_split('/[;\r\n]+/s', $model['attribute_alias']);
            $fields = array();
            foreach ($alias as &$value) {
                $val             = explode(':', $value);
                $fields[$val[0]] = $val[1];
            }
            foreach ($group as &$value) {
                foreach ($value as $key => $val) {
                    if (!empty($fields[$val['name']])) {
                        $value[$key]['title'] = $fields[$val['name']];
                    }
                }
            }
        }
        $attr = $group;
    }else{
        foreach ($list[$model_id] as $value) {
            $attr[$value['name']] = $value;
        }
    }
    return $attr;
}


/**
 * 检查$pos(推荐位的值)是否包含指定推荐位$contain
 * @param number $pos 推荐位的值
 * @param number $contain 指定推荐位
 * @return boolean true 包含 ， false 不包含
 * @author huajie <banhuajie@163.com>
 */
function check_document_position($pos = 0, $contain = 0){
    if(empty($pos) || empty($contain)){
        return false;
    }

    //将两个参数进行按位与运算，不为0则表示$contain属于$pos
    $res = $pos & $contain;
    if($res !== 0){
        return true;
    }else{
        return false;
    }
}


/**
 * 获取分类信息并缓存分类
 * @param  integer $id    分类ID
 * @param  string  $field 要获取的字段名
 * @return string         分类信息
 */
function get_category($id, $field = null){
    static $list;

    /* 非法分类ID */
    if(empty($id) || !is_numeric($id)){
        return '';
    }

    /* 读取缓存数据 */
    if(empty($list)){
        $list = S('sys_category_list');
    }

    /* 获取分类名称 */
    if(!isset($list[$id])){
        $cate = M('Category')->find($id);
        if(!$cate || 1 != $cate['status']){ //不存在分类，或分类被禁用
            return '';
        }
        $list[$id] = $cate;
        S('sys_category_list', $list); //更新缓存
    }
    return is_null($field) ? $list[$id] : $list[$id][$field];
}

/* 根据ID获取分类标识 */
function get_category_name($id){
    return get_category($id, 'name');
}

/* 根据ID获取分类名称 */
function get_category_title($id){
    return get_category($id, 'title');
}


/**
 * 获取参数的所有父级分类
 * @param int $cid 分类id
 * @return array 参数分类和父类的信息集合
 * @author huajie <banhuajie@163.com>
 */
function get_parent_category($cid){
    if(empty($cid)){
        return false;
    }
    $cates  =   M('Category')->where(array('status'=>1))->field('id,title,pid')->order('sort')->select();
    $child  =   get_category($cid); //获取参数分类的信息
    $pid    =   $child['pid'];
    $temp   =   array();
    $res[]  =   $child;
    while(true){
        foreach ($cates as $key=>$cate){
            if($cate['id'] == $pid){
                $pid = $cate['pid'];
                array_unshift($res, $cate); //将父分类插入到数组第一个元素前
            }
        }
        if($pid == 0){
            break;
        }
    }
    return $res;
}


/**
 * 获取文档封面图片
 * @param int $cover_id
 * @param string $field
 * @return 完整的数据  或者  指定的$field字段值
 * @author huajie <banhuajie@163.com>
 */
function get_cover($cover_id, $field = null){
    if(empty($cover_id)){
        return false;
    }
    $picture = M('Picture')->where(array('status'=>1))->getById($cover_id);
    if($field == 'path'){
        if(!empty($picture['url'])){
            $picture['path'] = $picture['url'];
        }else{
            $picture['path'] = __ROOT__.$picture['path'];
        }
    }
    return empty($field) ? $picture : $picture[$field];
}

function array_depth($array) {
    if(!is_array($array)) return 0;
    $max_depth = 1;
    foreach ($array as $value) {
        if (is_array($value)) {
            $depth = array_depth($value) + 1;

            if ($depth > $max_depth) {
                $max_depth = $depth;
            }
        }
    }
    return $max_depth;
}


/**
 * 根据用户ID获取用户昵称
 * @param  integer $uid 用户ID
 * @return string       用户昵称
 */
function get_nickname($uid = 0){
    static $list;
    if(!($uid && is_numeric($uid))){ //获取当前登录用户名
        return session('user_auth.nickname');
    }

    /* 获取缓存数据 */
    if(empty($list)){
        $list = S('sys_nickname_list');
    }

    /* 查找用户信息 */
    $key = "u{$uid}";
    if(isset($list[$key])){ //已缓存，直接使用
        $name = $list[$key];
    } else { //调用接口获取用户信息
        $info = M('Member')->field('nickname')->find($uid);
        if($info !== false && $info['nickname'] ){
            $nickname = $info['nickname'];
            $name = $list[$key] = $nickname;
            /* 缓存用户 */
            $count = count($list);
            $max   = 300;
            while ($count-- > $max) {
                array_shift($list);
            }
            S('sys_nickname_list', $list);
        } else {
            $name = '';
        }
    }
    return $name;
}

function get_user($uid = 0) {
    if(!($uid && is_numeric($uid))){ //获取当前登录用户名
        return false;
    }
    $info = M('User')->field('uid,openid,username,status,subscribe')->find($uid);

    return $info;
}

/**
 * 根据用户ID获取用户登录名
 * @param  integer $uid 用户ID
 * @return string       用户昵称
 */
function get_username($uid = 0){
    static $list;
    if(!($uid && is_numeric($uid))){ //获取当前登录用户名
        return session('user_auth.username');
    }

    /* 获取缓存数据 */
    if(empty($list)){
        $list = S('sys_username_list');
    }

    /* 查找用户信息 */
    $key = "u{$uid}";
    if(isset($list[$key])){ //已缓存，直接使用
        $name = $list[$key];
    } else { //调用接口获取用户信息
        $info = M('Member')->field('username')->find($uid);
        if($info !== false && $info['username'] ){
            $username = $info['username'];
            $name = $list[$key] = $username;
            /* 缓存用户 */
            $count = count($list);
            $max   = C('USER_MAX_CACHE');
            while ($count-- > $max) {
                array_shift($list);
            }
            S('sys_username_list', $list);
        } else {
            $name = '';
        }
    }
    return $name;
}


function get_images($ids,$field = true){
    if ( !is_array($ids) ){
        $ids = preg_split('/[,;\r\n]+/', trim($ids, ",;\r\n"));
    }
    $images = D('Picture')->field($field)->where(['id'=>['in',$ids]])->select();
    return $images;
}


/**
 * 刷新微信基础access_token函数.
 *
 * @param $that
 * @return bool
 */
function refresh_access_token($that){
    if ( !$that ){
        return false;
    }
    // 初始化微信工具类
    // 初始化参数
    $that->params([
        'options' => [
            'token' =>  C('WECHAT_TOKEN'),
            'encodingaeskey'    =>  C('WECHAT_ENCODINGAESKEY'),
            'appid' =>  C('WECHAT_APPID'),
            'appsecret'=>   C('WECHAT_APPSECRET')
        ]
    ]);

    // 从本地缓存中获取access_token
    $access_token_arr = S('WECHAT_ACCESS_TOKEN_'.C('WECHAT_ORIGINALID'));

    // 判断有无缓存，无：从数据库中读取
    if ( !$access_token_arr ) {
        $access_token_arr = $that['Wechat']->model()->info(['origional_id'=>C('WECHAT_ORIGIONALID')],'access_token,updated_at');
        trace('从数据库中获取access_token：'.$access_token_arr['access_token'],'wechat');
        S('WECHAT_ACCESS_TOKEN_'.C('WECHAT_ORIGINALID'),$access_token_arr);
    }

    // 本地缓存不存在或已过期,则更新access_token
    if ( !$access_token_arr['access_token'] || (time() - $access_token_arr['updated_at'] > 7000) ) {
        trace('access_token不存在或已过期','wechat');
        $that['Wechat']->resetAuth();
        if ( $access_token = $that['Wechat']->checkAuth() ) {
            // 获取到新的access_token
            S('WECHAT_ACCESS_TOKEN_'.C('WECHAT_ORIGINALID'),['updated_at' => time(),'access_token'=>$access_token]);
            trace('更新access_token成功:'.$access_token,'wechat');
            // 缓存到数据库
            $that['Wechat']->model()->where(['origional_id'=>C('WECHAT_ORIGIONALID')])->setField('access_token',$access_token);
            $that['Wechat']->model()->where(['origional_id'=>C('WECHAT_ORIGIONALID')])->setField('updated_at',time());
        } else {
            // 更新access_token失败
            trace('更新access_token失败','wechat');
        }
    } else {
        // 未经验证access_token是否有效，直接赋值
        $that['Wechat']->checkAuth('', '', $access_token_arr['access_token']);
        trace('从缓存中获取access_token： ' . $access_token_arr['access_token'], 'wechat');

        // 检查是否有效
        if ( !$server_ip = $that['Wechat']->getServerIp() ) {
            trace('缓存的access_token失效，删除缓存','wechat');
            S('WECHAT_ACCESS_TOKEN_'.C('WECHAT_ORIGINALID'),null);
            $that['Wechat']->model()->where(['origional_id'=>C('WECHAT_ORIGIONALID')])->setField('access_token','');
            refresh_access_token($that);
        }
    }
}


function in_wechat($str = null){
    if ( strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false ) {
		return $str?'true':true;
    }else{
		return $str?'false':false;
    }
}


/**
 * 微信登录函数.
 *
 * @param $that
 * @return bool|mixed
 */
function wechat_login($that){
    if ( !$that ){
        return false;
    }


    //判断是否是微信端
    if ( strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false ) {
        trace("微信端",'login');
    }else{
        trace("非微信端",'login');
        return false;
    }

    // 未登录状态下，检查是否有open_id，若有open_id则进行自动登录或增加用户记录
    if ( ! session('wechat.user') ) {

        // 更新access_token
        refresh_access_token($that);

        // 无code则跳转到微信Oauth
        if(!$_GET['code']){

            // 构建跳转url
            $url = $that['Wechat']->getOauthRedirect($callback="http://".$_SERVER["HTTP_HOST"].$_SERVER['PHP_SELF'].$_SERVER['REQUEST_URI'],$state='',$scope=C('WECHAT_SCOPE'));
            // 跳转
            redirect($url);

            // 需要强制结束php脚本
            exit;

        }else{
            // 获取access_token及openid
            $res = $that['Wechat']->getOauthAccessToken();
            $user = $that['Wechat']->getOauthUserinfo($res['access_token'], $res['openid']);
            trace($user['nickname'], 'login:wechat_user_nickname');

            session("wechat.user",$user);
        }
    }
    // 以open_id自动登录

    return $that['User']->loginByWechat(session('wechat.user'));


}


function check_login($that){
    if( !session('user.uid') ) {
        return wechat_login($that);
    }
    return session('user.uid');
}

function child_category($category_id,$field = true){
    $Category = D('Category');
    $list = $Category->where("pid=$category_id")->field($field)->select();
    return $list;
}

function time_format($time = null){
    if ($time) {
        echo date('Y-m-d', $time) . 'T' . date('H:i', $time);
    } else {
        $time = time();
        echo date('Y-m-d', $time) . 'T' . date('H:i', $time);
    }
}

function filter_ip($ip){
    return true;
}

/**
 * 对二维数组的某个键值进行搜索.
 *
 * @param array $array 搜索的2维数组
 * @param $key   mixed 键
 * @param $value mixed 值
 * @param bool $strict false:默认 不严格检查  true:严格检查
 * @return array
 */
function array_2_search(array $array, $key, $value, $strict = false) {
    $res = [];
    foreach($array as $v) {
        if (false === $strict) {
            if (isset($v[$key]) && $v[$key] == $value) {
                array_push($res,$v);
            }
        } else {
            if (isset($v[$key]) && $v[$key] === $value) {
                array_push($res,$v);
            }
        }
    }
    return $res;
}

